﻿using System;
using System.Timers;

namespace Digitalmes.Services.Data
{

    /// <summary>
    /// MES系统采样管理器
    /// 负责：入站-出站期间的定时数据采样、多工站并发控制、4小时超时自动终止
    /// </summary>
    public class SamplingManager :ISingleton, IDisposable
    {
        #region 私有字段
        // 线程安全集合：存储所有活跃采样任务（Key=唯一任务ID，Value=采样任务对象）
        private readonly ConcurrentDictionary<string, SamplingTask> _activeTasks = new ConcurrentDictionary<string, SamplingTask>();

        // 数据库操作锁：防止多线程并发并发调用存储过程导致的冲突
        private readonly object _databaseLock = new object();

        // 全局全局超时扫描定时器：定期检查并清理超期任务（兜底机制）
        private readonly Timer _globalTimeoutChecker;

       
      
        #endregion

        #region 构造与析构
        /// <summary>
        /// 初始化采样管理器
        /// </summary>
        public SamplingManager()
        {
            // 初始化全局超时检查器（每5分钟扫描一次）
            _globalTimeoutChecker = new Timer(TimeSpan.FromMinutes(2).TotalMilliseconds);
            _globalTimeoutChecker.Elapsed += GlobalTimeoutCheck;
            _globalTimeoutChecker.AutoReset = true;
            _globalTimeoutChecker.Start();
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            // 停止全局超时检查器
            _globalTimeoutChecker?.Stop();
            _globalTimeoutChecker?.Dispose();

            // 清理所有活跃任务
            foreach (var task in _activeTasks.Values)
            {
                task.SamplerTimer?.Stop();
                task.SamplerTimer?.Dispose();
            }
            _activeTasks.Clear();
        }
        #endregion

        #region 公共方法（入站/出站调用）
        /// <summary>
        /// 开始采样（入站时调用）
        /// </summary>
        /// <param name="taskId">唯一任务ID（如工站ID+订单号）</param>
        /// <param name="stationId">工站ID</param>
        /// <param name="sampleIntervalMs">采样间隔（毫秒，默认1秒）</param>
        public void StartSampling(string taskId, string stationId, int sampleIntervalMs = 1000)
        {
            // 验证参数
            if (string.IsNullOrEmpty(taskId))
                throw new ArgumentNullException(nameof(taskId), "任务ID不能为空");

            // 防止重复创建任务
            if (_activeTasks.ContainsKey(taskId))
                return;

            // 创建采样定时器 - 使用闭包关联taskId
            var samplerTimer = new Timer(sampleIntervalMs);
            // 使用闭包捕获当前taskId，解决Timer无Tag属性的问题
            samplerTimer.Elapsed += (sender, e) => SamplingTimer_Elapsed(sender, e, taskId);
            samplerTimer.AutoReset = true;
            samplerTimer.Start();

            // 创建任务对象并加入集合
            var task = new SamplingTask
            {
                TaskId = taskId,
                StationId = stationId,
                StartTime = DateTime.Now,
                SamplerTimer = samplerTimer,
                SampleInterval = sampleIntervalMs
            };

            _activeTasks.TryAdd(taskId, task);
        }

        /// <summary>
        /// 停止采样（出站时调用）
        /// </summary>
        /// <param name="taskId">唯一任务ID</param>
        public void StopSampling(string taskId)
        {
            // 从集合中移除并获取任务
            if (_activeTasks.TryRemove(taskId, out var task))
            {
                // 停止并释放定时器
                task.SamplerTimer?.Stop();
                task.SamplerTimer?.Dispose();

                // 记录出站时间
                task.EndTime = DateTime.Now;

                // 触发任务结束事件（可用于后续处理：如数据汇总）
                TaskCompleted?.Invoke(this, new TaskCompletedEventArgs(task));
            }
        }
        #endregion

        #region 私有方法（定时任务逻辑）
        /// <summary>
        /// 定时采样事件（增加taskId参数，通过闭包传递）
        /// </summary>
        private void SamplingTimer_Elapsed(object sender, ElapsedEventArgs e, string taskId)
        {
            // 验证任务是否存在
            if (!_activeTasks.TryGetValue(taskId, out var task))
                return;

            // 检查是否超时（超过4小时）
            if (DateTime.Now - task.StartTime > _activeTasks[taskId].MaxDuration)
            {
                task.IsTimeout = true;
                StopSampling(taskId); // 自动终止
                TimeoutOccurred?.Invoke(this, new TaskTimeoutEventArgs(task)); // 触发超时事件
                return;
            }

            // 执行采样（线程安全）
            lock (_databaseLock)
            {
                try
                {
                    // 调用存储过程读取数据（根据实际业务调整参数）
                    var sampleData = ExecuteSamplingProcedure(task.TaskId, task.StationId);

                    _activeTasks[taskId].CallBack?.Invoke(task.TaskId);

                    // 触发采样完成事件（可用于曲线绘制等后续处理）
                    SamplingCompleted?.Invoke(this, new SamplingCompletedEventArgs(task, sampleData));
                }
                catch (Exception ex)
                {
                    // 采样异常事件
                    SamplingFailed?.Invoke(this, new SamplingFailedEventArgs(task, ex));
                }
            }
        }

        /// <summary>
        /// 全局超时检查（兜底机制）
        /// </summary>
        private void GlobalTimeoutCheck(object sender, ElapsedEventArgs e)
        {
            // 筛选出所有超时未处理的任务
            var timeoutTaskIds = _activeTasks
                .Where(kv => DateTime.Now - kv.Value.StartTime > kv.Value.MaxDuration)
                .Select(kv => kv.Key)
                .ToList();

            // 终止超时任务
            foreach (var taskId in timeoutTaskIds)
            {
                if (_activeTasks.TryGetValue(taskId, out var task))
                    task.IsTimeout = true;

                StopSampling(taskId);
                TimeoutOccurred?.Invoke(this, new TaskTimeoutEventArgs(_activeTasks[taskId]));
            }
        }

        /// <summary>
        /// 执行采样存储过程（实际业务实现）
        /// </summary>
        private object ExecuteSamplingProcedure(string taskId, string stationId)
        {
            // 此处实现实际的存储过程调用逻辑
            // 示例：
            // using (var connection = new SqlConnection("你的数据库连接字符串"))
            // {
            //     connection.Open();
            //     using (var command = new SqlCommand("usp_ReadSamplingData", connection))
            //     {
            //         command.CommandType = CommandType.StoredProcedure;
            //         command.Parameters.AddWithValue("@TaskId", taskId);
            //         command.Parameters.AddWithValue("@StationId", stationId);
            //         using (var reader = command.ExecuteReader())
            //         {
            //             // 读取并返回采样数据
            //         }
            //     }
            // }
            return null;
        }
        #endregion

        #region 事件（用于外部订阅处理）
        /// <summary>
        /// 采样完成事件（可用于曲线数据收集）
        /// </summary>
        public event EventHandler<SamplingCompletedEventArgs> SamplingCompleted;

        /// <summary>
        /// 采样失败事件（可用于错误日志）
        /// </summary>
        public event EventHandler<SamplingFailedEventArgs> SamplingFailed;

        /// <summary>
        /// 任务超时事件（可用于告警）
        /// </summary>
        public event EventHandler<TaskTimeoutEventArgs> TimeoutOccurred;

        /// <summary>
        /// 任务完成事件（入站-出站流程结束）
        /// </summary>
        public event EventHandler<TaskCompletedEventArgs> TaskCompleted;
        #endregion
    }


    #region 辅助类与事件参数


    /// <summary>
    /// 采样完成事件参数
    /// </summary>
    public class SamplingCompletedEventArgs : EventArgs
    {
        public SamplingTask Task { get; }
        public object SampleData { get; }

        public SamplingCompletedEventArgs(SamplingTask task, object sampleData)
        {
            Task = task;
            SampleData = sampleData;
        }
    }

    /// <summary>
    /// 采样失败事件参数
    /// </summary>
    public class SamplingFailedEventArgs : EventArgs
    {
        public SamplingTask Task { get; }
        public Exception Exception { get; }

        public SamplingFailedEventArgs(SamplingTask task, Exception ex)
        {
            Task = task;
            Exception = ex;
        }
    }

    /// <summary>
    /// 任务超时事件参数
    /// </summary>
    public class TaskTimeoutEventArgs : EventArgs
    {
        public SamplingTask Task { get; }

        public TaskTimeoutEventArgs(SamplingTask task)
        {
            Task = task;
        }
    }

    /// <summary>
    /// 任务完成事件参数
    /// </summary>
    public class TaskCompletedEventArgs : EventArgs
    {
        public SamplingTask Task { get; }

        public TaskCompletedEventArgs(SamplingTask task)
        {
            Task = task;
        }
    }
    #endregion

}
